package Command; import java.nio.FloatBuffer; import java.util.StringTokenizer; import LDraw.Support.ColorLibrary; import LDraw.Support.LDrawDirective; import LDraw.Support.LDrawKeywords; import LDraw.Support.NSComparisonResult; import LDraw.Support.type.LDrawColorMaterialT; public class LDrawColor extends LDrawDirective implements Cloneable { /** * @uml.property name="colorCode" * @uml.associationEnd */ LDrawColorT colorCode; /** * @uml.property name="colorRGBA" multiplicity="(0 -1)" dimension="1" */ float colorRGBA[] = new float[4]; // range [0.0 - 1.0] /** * @uml.property name="edgeColorCode" * @uml.associationEnd */ LDrawColorT edgeColorCode; // == LDrawColorBogus if not used /** * @uml.property name="edgeColorRGBA" multiplicity="(0 -1)" dimension="1" */ float edgeColorRGBA[] = new float[4]; /** * @uml.property name="hasExplicitAlpha" */ boolean hasExplicitAlpha; /** * @uml.property name="hasLuminance" */ boolean hasLuminance; /** * @uml.property name="luminance" */ int luminance; /** * @uml.property name="material" * @uml.associationEnd */ LDrawColorMaterialT material; /** * @uml.property name="materialParameters" */ String materialParameters; /** * @uml.property name="name" */ String name; /** * @uml.property name="fakeComplimentColor" * @uml.associationEnd */ LDrawColor fakeComplimentColor; // synthesized, not according to !COLOUR // rules public LDrawColor() { init(); } // ========== init // ============================================================== // // Purpose: Initialize a new object. // // ============================================================================== public LDrawColor init() { super.init(); colorRGBA = new float[4]; setColorCode(LDrawColorT.LDrawColorBogus); setEdgeColorCode(LDrawColorT.LDrawColorBogus); setMaterial(LDrawColorMaterialT.LDrawColorMaterialNone); setName(""); colorRGBA[3] = 1.0f; // alpha. return this; }// end init // ========== finishParsing: // ==================================================== // // Purpose: -[LDrawMetaCommand initWithLines:inRange:] is // responsible for parsing out the line code and color command // (i.e., "0 !COLOUR"); now we just have to finish the // color-command specific syntax. // // ============================================================================== public boolean finishParsing(StringTokenizer strTokenizer) throws Exception { String parsedField = null; // Name // [scanner scanUpToCharactersFromSet:[NSCharacterSet // whitespaceCharacterSet] intoString:&field); parsedField = strTokenizer.nextToken(); setName(parsedField); // Color Code if (strTokenizer.hasMoreTokens() == false || strTokenizer.nextToken().equals("CODE") == false) throw new Exception("BricksmithParseExceptio: " + "Bad !COLOUR syntax"); if (strTokenizer.hasMoreTokens() == false) throw new Exception("BricksmithParseException: " + "Bad !COLOUR syntax"); parsedField = strTokenizer.nextToken(); int value = Integer.parseInt(parsedField); for (LDrawColorT color : LDrawColorT.values()) { if (color.getValue() == value) { colorCode = color; break; } } // Color Components if (strTokenizer.hasMoreTokens() == false || strTokenizer.nextToken().equals("VALUE") == false) throw new Exception("BricksmithParseExceptio: " + "Bad !COLOUR syntax"); if (strTokenizer.hasMoreTokens() == false) throw new Exception("BricksmithParseException: " + "Bad !COLOUR syntax"); parsedField = strTokenizer.nextToken(); colorRGBA[0] = Integer.parseInt(parsedField.substring(1, 3), 16) / 255.0f; colorRGBA[1] = Integer.parseInt(parsedField.substring(3, 5), 16) / 255.0f; colorRGBA[2] = Integer.parseInt(parsedField.substring(5), 16) / 255.0f; colorRGBA[3] = 1.0f; // // // Edge if (strTokenizer.hasMoreTokens() == false || strTokenizer.nextToken().equals("EDGE") == false) throw new Exception("BricksmithParseExceptio: " + "Bad !COLOUR syntax"); if (strTokenizer.hasMoreTokens() == false) throw new Exception("BricksmithParseException: " + "Bad !COLOUR syntax"); parsedField = strTokenizer.nextToken(); if (parsedField.length() == 7) { edgeColorRGBA[0] = Integer .parseInt(parsedField.substring(1, 3), 16) / 255.0f; edgeColorRGBA[1] = Integer .parseInt(parsedField.substring(3, 5), 16) / 255.0f; edgeColorRGBA[2] = Integer.parseInt(parsedField.substring(5), 16) / 255.0f; edgeColorRGBA[3] = 1.0f; } else { value = Integer.parseInt(parsedField); for (LDrawColorT color : LDrawColorT.values()) { if (color.getValue() == value) { edgeColorCode = color; break; } } } // Optional Fields while (strTokenizer.hasMoreTokens()) { parsedField = strTokenizer.nextToken(); if (parsedField.equals("ALPHA")) { // - Alpha value = Integer.parseInt(strTokenizer.nextToken()); colorRGBA[3] = value / 255.0f; hasExplicitAlpha = true; } else if (parsedField.equals("LUMINANCE")) { // - Luminance value = Integer.parseInt(strTokenizer.nextToken()); setLuminance(value); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_CHROME)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialChrome); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_PEARLESCENT)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialPearlescent); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_RUBBER)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialRubber); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_MATTE_METALLIC)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialMatteMetallic); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_METAL)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialMetal); }else if (parsedField.equals(LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_CUSTOM)) { setMaterial(LDrawColorMaterialT.LDrawColorMaterialCustom); String parameters = ""; while (strTokenizer.hasMoreTokens()) { parameters += strTokenizer.nextToken()+" "; } setMaterialParameters(parameters); } } return true; }// end lineWithDirectiveText // ---------- blendedColorForCode: // ------------------------------------[static]-- // // Purpose: Returns pseduocolors according to logic found in LDRAW.EXE. // // Notes: James Jessiman's original DOS-based LDraw was limited in to 16 // colors (in 1995!), so he developed a hack to accommodate a // bigger palette: dithering. Two colors would be combined in a // pixel-checkerboard pattern. Transparent colors were implemented // with a dither overlay, as was a huge swath of color codes which // would combine two colors. // // All of this is utterly, pathologically obsolete. For one thing, // computers can display 16.7 million colors per pixel. For another // thing, dithering was really ugly. And finally, LDConfig and the // !COLOUR meta-command provide a way of specifying any one of // those 16.7 million colors. // // Unfortunately, MLCad displayed dithered colors in its color // picker up until 2010. Worse yet, woe betide us, part authors // used these dithered colors to model certain stickers and printed // bricks. // // Bricksmith will grudgingly support blended colors strictly for // purposes of displaying those stickers. But it will falseT, EVER // show these colors in its color picker. This functionality should // be sent back to the early nineties where it deserved to die. // // ------------------------------------------------------------------------------ public static LDrawColor blendedColorForCode(LDrawColorT colorCode) { int ldrawEXEColorTable[][] = { { 51, 51, 51 }, { 0, 51, 178 }, { 0, 127, 51 }, { 0, 181, 166 }, { 204, 0, 0 }, { 255, 51, 153 }, { 102, 51, 0 }, { 153, 153, 153 }, { 102, 102, 88 }, { 0, 128, 255 }, { 51, 255, 102 }, { 171, 253, 249 }, { 255, 0, 0 }, { 255, 176, 204 }, { 255, 229, 0 }, { 255, 255, 255 } }; int blendCode1 = 0; int blendCode2 = 0; float[] blendedComponents = new float[4]; LDrawColor blendedColor = new LDrawColor(); blendedColor.init(); // Find the two base indexes of the blended color's dither. blendCode1 = (colorCode.getValue() - 256) / 16; // div (integer division) blendCode2 = (colorCode.getValue() - 256) % 16; // Derive the components. Hold your nose. // Obviously, we don't support dithering. We average the colors to // produce // something which looks nicer. blendedComponents[0] = (float) (ldrawEXEColorTable[blendCode1][0] + ldrawEXEColorTable[blendCode2][0]) / 2 / 255; // red blendedComponents[1] = (float) (ldrawEXEColorTable[blendCode1][1] + ldrawEXEColorTable[blendCode2][1]) / 2 / 255; // green blendedComponents[2] = (float) (ldrawEXEColorTable[blendCode1][2] + ldrawEXEColorTable[blendCode2][2]) / 2 / 255; // blue blendedComponents[3] = 1.0f; // alpha // Create a color to hold them. blendedColor.setColorCode(colorCode); blendedColor.setColorRGBA(blendedComponents); blendedColor.setName("BlendedColor" + colorCode.getValue()); return blendedColor; }// end blendedColorForCode: // #pragma mark - // #pragma mark DIRECTIVES // #pragma mark - // ========== draw:viewScale:parentColor: // ======================================= // // Purpose: "Draws" the color. // // ============================================================================== public void collectColor() { // Need to add this color to the model's color library. ColorLibrary colorLibrary = (ColorLibrary) enclosingDirective() .enclosingModel().colorLibrary(); colorLibrary.addColor(this); }// end draw:viewScale:parentColor: // ========== write // ============================================================= // // Purpose: Returns a line that can be written out to a file. // Line format: // 0 !COLOUR name CODE x VALUE v EDGE e [ALPHA a] [LUMINANCE l] // [ CHROME | PEARLESCENT | RUBBER | MATTE_METALLIC | // METAL | MATERIAL <params> ]</params> // // Notes: This does not try to preserve spacing a la ldconfig.ldr, mainly // because %17@ doesn't work. // // ============================================================================== public String write() { String line = null; line = String.format("0 %s %s %s %d %s %s", // | | | LDrawKeywords.LDRAW_COLOR_DEFINITION, name(), // | | LDrawKeywords.LDRAW_COLOR_DEF_CODE, colorCode, // | LDrawKeywords.LDRAW_COLOR_DEF_VALUE, hexStringForRGB(colorRGBA)); // if(edgeColorCode() == LDrawColorT.LDrawColorBogus) // line+= new String().format(" %s %s", // LDrawKeywords.LDRAW_COLOR_DEF_EDGE, hexStringForRGB(edgeColorRGBA); // else // line+= new String().format(" %s %d", // LDrawKeywords.LDRAW_COLOR_DEF_EDGE, edgeColorCode)); // // if(hasExplicitAlpha == true) // line+= new String().format(" %s %d", // LDrawKeywords.LDRAW_COLOR_DEF_ALPHA, (int)(colorRGBA[3] * 255)); // // if(hasLuminance == true) // line+= new String().format(" %s %d", // LDrawKeywords.LDRAW_COLOR_DEF_LUMINANCE, luminance); // // switch(material) // { // case LDrawColorMaterialNone: // break; // // case LDrawColorMaterialChrome: // line+= new String().format(" %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_CHROME); // break; // // case LDrawColorMaterialPearlescent: // line+= new String().format(" %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_PEARLESCENT); // break; // // case LDrawColorMaterialRubber: // line+= new String().format(" %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_RUBBER); // break; // // case LDrawColorMaterialMatteMetallic: // line+= new String().format(" %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_MATTE_METALLIC); // break; // // case LDrawColorMaterialMetal: // line+= new String().format(" %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_METAL); // break; // // case LDrawColorMaterialCustom: // line+= new String().format(" %s %s", // LDrawKeywords.LDRAW_COLOR_DEF_MATERIAL_CUSTOM, materialParameters); // break; // } return line; }// end write // #pragma mark - // #pragma mark DISPLAY // #pragma mark - // ========== browsingDescription // =============================================== // // Purpose: Returns a representation of the directive as a short string // which can be presented to the user. // // ============================================================================== public String browsingDescription() { return name(); }// end browsingDescription // ========== iconName // ========================================================== // // Purpose: Returns the name of image file used to display this kind of // object, or null if there is no icon. // // ============================================================================== public String iconName() { return "ColorDroplet"; }// end iconName // ========== inspectorClassName // ================================================ // // Purpose: Returns the name of the class used to inspect this one. // // ============================================================================== public String inspectorClassName() { return null; }// end inspectorClassName // #pragma mark - // #pragma mark ACCESSORS // #pragma mark - // ========== colorCode // ========================================================= // ============================================================================== public LDrawColorT colorCode() { return colorCode; }// end colorCode // ========== complimentColor // =================================================== // // Purpose: Returns the color which should be used for drawing // LDrawEdgeColor for this color. // // ============================================================================== public LDrawColor complimentColor() { // LDConfig compliment colors look ugly. Bricksmith uses // internally-derived // compliments which look more like the original LDraw. if (fakeComplimentColor == null) { fakeComplimentColor = new LDrawColor(); fakeComplimentColor.init(); float fakeComplimentComponents[] = new float[4]; // complimentColor(colorRGBA, fakeComplimentComponents); fakeComplimentColor.setColorCode(LDrawColorT.LDrawEdgeColor); fakeComplimentColor.setColorRGBA(fakeComplimentComponents); } return fakeComplimentColor; } // ========== edgeColorCode // ===================================================== // // Purpose: Return the LDraw color code to be used when drawing the // compilement of this color. If the compliment is stored as actual // components instead, this call will return LDrawColorBogus. When // that code is encountered, you should instead call edgeColorRGBA // for the actual color values. // // ============================================================================== public LDrawColorT edgeColorCode() { return edgeColorCode; }// end edgeColorCode // ========== getColorRGBA: // ===================================================== // // Purpose: Fills the inComponents array with the RGBA components of this // color. // // ============================================================================== public void getColorRGBA(float inComponents[]) { // memcpy(inComponents, colorRGBA, sizeof(float) * 4); for (int i = 0; i < 4; i++) inComponents[i] = colorRGBA[i]; }// end getColorRGBA: // ========== getEdgeColorRGBA: // ================================================= // // Purpose: Returns the actual color components specified for the compliment // of this color. // // Notes: These values MAY falseT BE VALID. To determine if they are in // force, you must first call -edgeColorCode. If it returns a value // other than LDrawColorBogus, look up the color for that code // instead. Otherwise, use the values returned by this method. // // ============================================================================== public void getEdgeColorRGBA(float inComponents[]) { for (int i = 0; i < 4; i++) inComponents[i] = edgeColorRGBA[i]; }// end getEdgeColorRGBA: // ========== localizedName // ===================================================== // // Purpose: Returns the name for the specified color code. If possible, the // name will be localized. For colors which have no localization // defined, this will default to the actual color name from the // config file, with any underscores converted to spaces. // // Notes: If, in some bizarre aberration, this color has a code // corresponding to a standard LDraw code, but the color is falseT // actually representing this color, you will get the localized // name of the standard color. Deal with it. // // ============================================================================== public String localizedName() { String nameKey = null; String colorName = null; // Find the color's name in the localized string file. // Color names are conveniently keyed. nameKey = String.format("LDraw: %d", colorCode); colorName = nameKey;// NSLocalizedString(nameKey , null); // If no localization was defined, then fall back on the name defined in // the // color directive. if (colorName == nameKey) { // Since spaces are verboten in !COLOUR directives, color names tend // to // have a bunch of unsightly underscores in them. We don't want to // show // that to the user. String fixedName = name; fixedName.replaceAll("_", " "); colorName = fixedName; // Alas! 10.5 only! // colorName = [name] stringByReplacingOccurrencesOfString:@"_" // withString:@" "); } return colorName; }// end localizedName // ========== luminance // ========================================================= // ============================================================================== public int luminance() { return luminance; }// end luminance // ========== material // ========================================================== // ============================================================================== public LDrawColorMaterialT material() { return material; }// end material // ========== materialParameters // ================================================ // ============================================================================== public String materialParameters() { return materialParameters; }// end materialParameters // ========== name // ============================================================== // ============================================================================== public String name() { return name; }// end name // #pragma mark - // ========== setColorCode: // ===================================================== // // Purpose: Sets the LDraw integer code for this color. // // ============================================================================== /** * @param newCode * @uml.property name="colorCode" */ public void setColorCode(LDrawColorT newCode) { colorCode = newCode; }// end setColorCode: // ========== setColorRGBA: // ===================================================== // // Purpose: Sets the actual RGBA component values for this color. // // ============================================================================== public void setColorRGBA(float newComponents[]) { // memcpy(colorRGBA, newComponents, sizeof(float[4])); for (int i = 0; i < 4; i++) colorRGBA[i] = newComponents[i]; }// end setColorRGBA: // ========== setEdgeColorCode: // ================================================= // // Purpose: Sets the code of the color to use as this color's compliment // color. That value will have to be resolved by the color library. // // Notes: Edge colors may be specified either as real color components or // as a color-code reference. Only one is valid. To signal that the // components should be used instead of this color code, pass // LDrawColorBogus. // // ============================================================================== /** * @param newCode * @uml.property name="edgeColorCode" */ public void setEdgeColorCode(LDrawColorT newCode) { edgeColorCode = newCode; }// end setEdgeColorCode: // ========== setEdgeColorRGBA: // ================================================= // // Purpose: Sets actual color components for the edge color. // // Notes: Edge colors may be specified either as real color components or // as a color-code reference. Only one is valid. If you call this // method, it is assumed you are choosing the components variation. // The edge color code will automatically be set to // LDrawColorBogus. // // ============================================================================== public void setEdgeColorRGBA(float newComponents[]) { // memcpy(edgeColorRGBA, newComponents, sizeof(float[4])); for (int i = 0; i < 4; i++) edgeColorRGBA[i] = newComponents[i]; // Disable the edge color code, since we have real color values for it // now. setEdgeColorCode(LDrawColorT.LDrawColorBogus); }// end setEdgeColorRGBA: // ========== setLuminance: // ===================================================== // // Purpose: Brightness for colors that glow (range 0-255). Luminance is not // generally used by LDraw renderers (including this one), but may // be used for translation to other rendering systems. LUMINANCE is // optional. // // ============================================================================== /** * @param newValue * @uml.property name="luminance" */ public void setLuminance(int newValue) { luminance = newValue; hasLuminance = true; }// end setLuminance: // ========== setMaterial: // ====================================================== // // Purpose: Sets the material associated with this color. // // Notes: Bricksmith doesn't use this value, it just preserves it in the // color directive. // // ============================================================================== /** * @param newValue * @uml.property name="material" */ public void setMaterial(LDrawColorMaterialT newValue) { material = newValue; }// end setMaterial: // ========== setMaterialParameters: // ============================================ // // Purpose: Custom (implementation-dependent) values associated with a // custom material. // // Notes: Bricksmith doesn't use this value, it just preserves it in the // color directive. // // ============================================================================== /** * @param newValue * @uml.property name="materialParameters" */ public void setMaterialParameters(String newValue) { materialParameters = newValue; }// end setMaterialParameters: // ========== setName: // ========================================================== // // Purpose: Sets the name of the color. Spaces are represented by // underscores. // // ============================================================================== /** * @param newName * @uml.property name="name" */ public void setName(String newName) { name = newName; }// end setName: // #pragma mark - // #pragma mark UTILITIES // #pragma mark - // ========== isEqual: // ========================================================== // // Purpose: Allow these objects to serve as keys in a dictionary (used in // LDrawVertexes); -isEqual: and -hash are both required. // // We only expect one instance of each unique color to exist, so // the trivial comparison should be valid. After all, two different // (file-local) colors could share the same color code, but they // aren't equal. // // ============================================================================== public boolean isEqual(LDrawColor anObject) { boolean isEqual = false; // If two objects are equal, they must return the same hash. The hash is // a // pain to compute, so we don't want to do anything fancy with equality. // if([anObject isMemberOfClass:[LDrawColor class]]) // { // isEqual = (colorCode == [anObject colorCode]); // } isEqual = (anObject == this); return isEqual; } // ========== hash // ============================================================== // // Purpose: Allow these objects to serve as keys in a dictionary (used in // LDrawVertexes). // // ============================================================================== public Object hash() { return this; } // ========== compare: // ========================================================== // // Purpose: Compatibility method directing to our specialized comparison. // // ============================================================================== public NSComparisonResult compare(LDrawColor otherColor) { return HSVACompare(otherColor); } // ========== HSVACompare: // ====================================================== // // Purpose: Orders colors according to their Hue, Saturation, and // Brightness. // // ============================================================================== public NSComparisonResult HSVACompare(LDrawColor otherColor) { // NSComparisonResult result = NSOrderedSame; // float ourHSV[] = new float[4]; // float otherColorHSV[] = new float[4]; // // // Convert both to Hue-saturation-brightness // RGBtoHSV(colorRGBA[0], colorRGBA[1], colorRGBA[2], // ourHSV[0], ourHSV[1], ourHSV[2]); // // RGBtoHSV(otherColor.colorRGBA[0], otherColor.colorRGBA[1], // otherColor.colorRGBA[2], // otherColorHSV[0], otherColorHSV[1], otherColorHSV[2]); // // // Alpha // ourHSV[3] = colorRGBA[3]; // otherColorHSV[3] = colorRGBA[3]; // // // Hue // if( ourHSV[0] > otherColorHSV[0] ) // result = NSOrderedDescending; // else if( ourHSV[0] < otherColorHSV[0] ) // result = NSOrderedAscending; // else // { // // Saturation // if( ourHSV[1] > otherColorHSV[1] ) // result = NSOrderedDescending; // else if( ourHSV[1] < otherColorHSV[1] ) // result = NSOrderedAscending; // else // { // // Brightness // if( ourHSV[2] > otherColorHSV[2] ) // result = NSOrderedDescending; // else if( ourHSV[2] < otherColorHSV[2] ) // result = NSOrderedAscending; // else // { // // Alpha // if( ourHSV[3] > otherColorHSV[3] ) // result = NSOrderedDescending; // else if( ourHSV[3] < otherColorHSV[3] ) // result = NSOrderedAscending; // else // { // result = NSOrderedSame; // } // } // } // } // return result; return null; }// end HSVACompare: // ========== hexStringForRGB: // ================================================== // // Purpose: Returns a hex string for the given RGB components, formatted in // the syntax required by the LDraw Colour Definition Language // extension. // // ============================================================================== public String hexStringForRGB(float[] components) { String hexString = String.format("#%02X%02X%02X", (int) (components[0] * 255), (int) (components[1] * 255), (int) (components[2] * 255)); return hexString; }// end hexStringForRGB: // ========== scanHexString:intoRGB: // ============================================ // // Purpose: Parses the given Hexidecimal string into the first three // elements of the components array, dividing each hexidecimal byte // by 255. // // Notes: hexString must be prefixed by either "#" or "0x". The LDraw spec // is not clear on the case of the hex letters; we will assume both // are valid. // // Example: #77CC00 becomes (R = 0.4666; G = 0.8; B = 0.0) // // ============================================================================== public static boolean scanHexString(String hexScanner, float components[]) { boolean success = false; String hexStr = null; // Make sure it has the required prefix, whichever it might be // todo if (hexScanner.contains("#") == true) { int index = hexScanner.indexOf("#"); hexStr = hexScanner.substring(index + 1, index + 7); } else if (hexScanner.contains("0x") == true) { int index = hexScanner.indexOf("0x"); hexStr = hexScanner.substring(index + 1, index + 7); } if (hexStr != null) { // Scan the hex bytes into a packed integer, because that's the // easiest // thing to do with this NSScanner API. // hexScanner.scanHexInt(hexBytes); // Colors will be stored in the integer as follows: xxRRGGBB int value = Integer.parseInt(hexStr.substring(0, 2), 16); components[0] = (float) (value / 255); // Red value = Integer.parseInt(hexStr.substring(2, 4), 16); components[1] = (float) (value / 255); // Green value = Integer.parseInt(hexStr.substring(4, 6), 16); components[2] = (float) (value / 255); // Blue components[3] = 1.0f; // we shall assume alpha } return success; }// end parseHexString:intoRGB: // // #pragma mark - // #pragma mark DESTRUCTOR // #pragma mark - // #pragma mark - // ========== RGBtoHSV // ========================================================== // // Purpose: Converts an RGB color into Hue-Saturation-Brightness // // Parameters: r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1] // if s == 0, then h = -1 (undefined) // // Notes: from http://www.cs.rit.edu/~ncs/color/t_convert.html // // ============================================================================== void RGBtoHSV(float r, float g, float b, FloatBuffer h, FloatBuffer s, FloatBuffer v) { float min, max, delta; min = Math.min(r, Math.min(g, b)); max = Math.max(r, Math.max(g, b)); v.put(0, max); // v delta = max - min; if (max != 0) s.put(0, delta / max); // s else { // r = g = b = 0 // s = 0, v is undefined s.put(0, 0); h.put(0, -1); return; } if (r == max) h.put(0, (g - b) / delta); // between yellow & magenta else if (g == max) h.put(0, 2 + (b - r) / delta); // between cyan & yellow else h.put(0, 4 + (r - g) / delta); // between magenta & cyan h.put(0, h.get(0) * 60); // degrees if (h.get(0) < 0) h.put(0, h.get(0) + 360); } // ========== HSVtoRGB // ========================================================== // // Purpose: Converts an HSV color into Red-Green-Blue // // Parameters: r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1] // if s == 0, then h = -1 (undefined) // // Notes: from http://www.cs.rit.edu/~ncs/color/t_convert.html // // ============================================================================== void HSVtoRGB(float h, float s, float v, FloatBuffer r, FloatBuffer g, FloatBuffer b) { int i; float f, p, q, t; if (s == 0) { // achromatic (grey) r.put(0, v); g.put(0, v); b.put(0, v); return; } h /= 60; // sector 0 to 5 i = (int) Math.floor(h); f = h - i; // factorial part of h p = v * (1 - s); q = v * (1 - s * f); t = v * (1 - s * (1 - f)); switch (i) { case 0: r.put(v); g.put(t); b.put(p); break; case 1: r.put(q); g.put(v); b.put(p); break; case 2: r.put(p); g.put(v); b.put(t); break; case 3: r.put(p); g.put(q); b.put(v); break; case 4: r.put(t); g.put(p); b.put(v); break; default: // case 5: r.put(v); g.put(p); b.put(q); break; } } /** * @return * @uml.property name="colorCode" */ public LDrawColorT getColorCode() { return colorCode; } public Object clone() throws CloneNotSupportedException { return super.clone(); } }